package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	iplocation "gitee.com/thubcc/blockchain/iplocationservice"
	ws "gitee.com/thubcc/blockchain/websocket"
	"github.com/gorilla/websocket"
)

type Res struct{
    Longitude float64
    Latitude  float64
    IPV4      string
}
var (
	toUI   = make(chan Res,5)
	fromUI = make(chan string)
	db = &iplocation.IPDB{DBFile:".resources/GeoLite2-City.mmdb"}
	log = make(map[string]string)
)

func SetupWs() {
	w,err := ws.NewWsServer("ws://127.0.0.1:9001/msg")
	if err != nil {
		fmt.Println("Error setup Ws",err)
	}

    stopCh := make(chan int)
	send := func(conn *websocket.Conn) {
		for{
			select {
			case <-stopCh:
				fmt.Println("connect closed")
				return
			case ipv4 := <-toUI:
				data,_ := json.Marshal(ipv4);
				err := conn.WriteMessage(1, []byte(data))
				if err != nil {
					fmt.Println("send msg faild ", err)
            		return
				}
				<-time.After(time.Microsecond * 100)
			}
		}
	}
	wsHandle := func(conn *websocket.Conn) {
		defer func() {
			conn.Close()
			close(stopCh)
		}()
		go send(conn)
    	for {
        	conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(60000)))
       		_, msg, err := conn.ReadMessage()
        	if err != nil {
            	close(stopCh)
            	// 判断是不是超时
            	if netErr, ok := err.(net.Error); ok {
                	if netErr.Timeout() {
                    	fmt.Printf("ReadMessage timeout remote: %v\n", conn.RemoteAddr())
						return
					}
				}
				// 其他错误，如果是 1001 和 1000 就不打印日志
				if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) {
					fmt.Printf("ReadMessage other remote:%v error: %v \n", conn.RemoteAddr(), err)
				}
				return
        	}
			fmt.Println("收到消息：", string(msg))
			// fromUI <- string(msg)
    	}
	}
	w.RegistHandle(wsHandle)
	w.Start()
}
func Log(conn net.Conn) {
	var buf = make([]byte,1024)
	var output = bufio.NewWriter(os.Stdout)
	for {
		len, err := conn.Read(buf)
		if err!=nil {
			fmt.Println(err)
			return
		}
		output.Write(buf[:len])
	}
}
func processIp(i int,p *record) {
	if addr,ok := log[p.ID]; ok && addr!=""{
		return
	}
	fmt.Printf("%5d %s %s\n",i,p.ID,p.Addr)
	if p.ID == "" {
		return
	}
	log[p.ID] = p.Addr
	Longitude,Latitude,err := db.Location(p.Addr)
	if err != nil {
		fmt.Printf("read addr %s failure: %v\n",p.Addr,err)
		return
	} 
	var ipr = Res{
		Longitude,
		Latitude,
		p.Addr,
	}
	select{
	case toUI<-ipr:
	default:
		return
	}
}

func dumpLog(conn net.Conn) {
	err := db.Init()
	if err != nil {
		fmt.Errorf("open db failure: %v",err)
	}
	defer db.Close()

	var reader = bufio.NewReader(conn)
	for i:=0;;i++ {
		line,err := reader.ReadString('\n')
		if err != nil {
			fmt.Println(err)
			return
		}
		var p = record{}
		err = json.Unmarshal([]byte(line), &p)
		if err == nil {
			processIp(i,&p)
		}
	}
}

type record struct {
	Addr string `json:"addr"`
	ID   string `json:"id"`
}
func main() {
	go SetupWs()	
	var uAddr = net.UDPAddr{net.IPv4(127, 0, 0, 1),9000,""}
	conn, err := net.ListenUDP("udp", &uAddr)
	if err != nil {
		fmt.Println(err)
		return
	} else {
		fmt.Println("Listening",conn.LocalAddr().String())
	}
	defer conn.Close()
	go dumpLog(conn)
	input := bufio.NewReader(os.Stdin)
	fmt.Println()
	for {
		txt, err := input.ReadString('\n')
		if err != nil {
			fmt.Println("\n ~Q for exit:",err)
		} else {
			txt = strings.TrimRight(txt, "\n\r")
			if txt == "~Q" {
				break
			}
			fmt.Println(txt)
		}
	}
}